#ifndef __COMPONENT_PLAYER_H__
#define __COMPONENT_PLAYER_H__

#include <memory>
#include <vector>
#include <queue>
#include "Component.hpp"
#include "Engine/Ray3.h"
#include "Engine/Vector3.hpp"
#include "Engine/Matrix.h"
#include "Game/TerrainRaycastResult.hpp"
#include "Game/IInventory.hpp"
#include "GameStack.hpp"

using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    struct ComponentMiner;
    struct ComponentBody;
    struct ComponentAttacker;
    struct ComponentLevel;
    struct ComponentHealth;
    struct ComponentSickness;
    struct ComponentFlu;
    struct ComponentVitalStats;
    struct ComponentSleep;
    struct ComponentClothing;
    struct ComponentCreativeInventory;
    struct ComponentInventory;
    struct ComponentCraftingTable;
    struct ComponentAntiCheat;

    class PlayerData;

    enum class PlayerInteractEvent
	{
		None,
		Start,
		Place
	};

	enum class PlayerAimEvent
	{
		None,
		InProgress,
		Cancel,
		Complete
	};

	enum class PlayerDigEvent
	{
		None,
		Start,
		Cancel,
		End
	};

    struct DigEventItem
    {
        PlayerDigEvent digEvent = PlayerDigEvent::None;
        std::shared_ptr<Ray3> digRay = nullptr;
        std::shared_ptr<TerrainRaycastResult> digRaycast = nullptr;
    };

    struct AimEventItem
    {
        PlayerAimEvent aimEvent = PlayerAimEvent::None;
        std::shared_ptr<Ray3> aim = nullptr;
    };

    struct InteractEventItem
    {
        PlayerInteractEvent interactEvent;
        Ray3 interactRay;
        std::shared_ptr<TerrainRaycastResult> placeRaycast;
    };

    struct HitEventItem
    {
        uint16_t entityID;
        Vector3 hitPosition;
        Vector3 hitDirection;
    };

    struct ComponentPlayer : public Component
    {
        bool constantSpawn;
        std::shared_ptr<PlayerData> playerData;

        ComponentBody* componentBody;
        ComponentMiner *componentMiner;
        ComponentAttacker *componentAttacker;
        ComponentLevel *componentLevel;
        ComponentHealth *componentHealth;
        ComponentSickness *componentSickness;
        ComponentFlu *componentFlu;
        ComponentVitalStats *componentVitalStats;
        ComponentSleep *componentSleep;
        ComponentClothing *componentClothing;
        ComponentCreativeInventory *componentCreativeInventory;
        ComponentInventory *componentInventory;
        ComponentCraftingTable *componentCraftingTable;
        ComponentAntiCheat *componentAntiCheat;


        DigEventItem digEventItem;
        AimEventItem aimEventItem;
        std::queue<DigEventItem> digEvents;
        std::queue<AimEventItem> aimEvents;
        std::queue<InteractEventItem> interactEvents;
        GameStack<HitEventItem> hitEvents;
        
        std::shared_ptr<Ray3>  pickBlockRay3 = nullptr;

        virtual void update(float dt) override;
        virtual const std::string &getName() const override;
        static const std::string &GetName();
        virtual void load(const nlohmann::json &jsonData) override;
        virtual void save(nlohmann::json &jsonData) override;
        virtual void saveToMsgJson(nlohmann::json &jsonData) override;

        inline void addDigEvent(PlayerDigEvent digEvent, std::shared_ptr<Ray3> digRay3, std::shared_ptr<TerrainRaycastResult> digRaycast);
        inline void addAimEvent(PlayerAimEvent aimEvent, std::shared_ptr<Ray3> aim);
        inline void addInteractEvent(PlayerInteractEvent interactEvent, const Ray3 &interactRay, std::shared_ptr<TerrainRaycastResult> placeRaycast);
        inline void addHitEvent(uint16_t entityID, const Vector3& hitPosition, const Vector3& hitDirection);

        // 丢弃手中的物品
        void doDrop();
        void dragDrop(const Vector3 &dropVelocity, IInventory *inventory, uint32_t slotIndex, uint32_t count);

        /**
         * @brief 将玩家传送到对应的位置上
         * @param position 位置
         */
        void setNetPosition(const Vector3 &position);
    };

    inline void ComponentPlayer::addDigEvent(PlayerDigEvent digEvent, std::shared_ptr<Ray3> digRay3, std::shared_ptr<TerrainRaycastResult> digRaycast)
    {
        digEvents.push(DigEventItem{ digEvent, digRay3, digRaycast});
    }
    inline void ComponentPlayer::addAimEvent(PlayerAimEvent aimEvent, std::shared_ptr<Ray3> aim)
    {
        aimEvents.push(AimEventItem{ aimEvent, aim });
    }
    inline void ComponentPlayer::addInteractEvent(PlayerInteractEvent interactEvent, const Ray3 &interactRay, std::shared_ptr<TerrainRaycastResult> placeRaycast)
    {
        interactEvents.push(InteractEventItem{ interactEvent, interactRay, placeRaycast });
    }
    inline void ComponentPlayer::addHitEvent(uint16_t entityID, const Vector3& hitPosition, const Vector3& hitDirection)
    {
        hitEvents.push(HitEventItem { entityID, hitPosition, hitDirection });
    }

} // namespace PocketSurvival

#endif
